// 是否为有效数组: 是数组且length > 0
function isValidArray (obj) {
  return Array.isArray(obj) && obj.length
}

// 查找code对应节点(返回第一个符合条件的节点)
export function getLeafByKey (key, keyName, list) {
  let result
  if (!isValidArray(list)) {
    return result
  }

  for (let i = 0; i < list.length; i++) {
    const item = list[i]
    if (item[keyName] === key) {
      result = item
    } else if (isValidArray(item.children)) {
      result = getLeafByKey(key, keyName, item.children)
    }
    if (result) {
      break
    }
  }

  return result
}

// 递归找到第一个叶子节点并将其返回
export function getFirstLeafNode (list) {
  let result
  if (!isValidArray(list)) {
    return result
  }

  for (let i = 0; i < list.length; i++) {
    const item = list[i]
    if (isValidArray(item.children)) {
      result = getFirstLeafNode(item.children)
    } else {
      result = item
    }

    if (result) {
      break
    }
  }

  return result
}

// 递归找到第一个被选中的叶子节点
export function getFirstCheckedLeafNode (list, checkKey = 'checked') {
  let result
  if (!isValidArray(list)) {
    return result
  }

  for (let i = 0; i < list.length; i++) {
    const item = list[i]
    if (isValidArray(item.children)) {
      result = getFirstLeafNode(item.children)
    } else if (item[checkKey]) {
      result = item
    }

    if (result) {
      break
    }
  }

  return result
}

// 递归找到所有叶子节点
export function getLeafNodes (source, result = []) {
  if (!source) {
    return result
  }

  const list = source.children
  if (!isValidArray(list)) {
    result.push(source)
    return result
  }

  for (let i = 0; i < list.length; i++) {
    const item = list[i]
    if (isValidArray(item.children)) {
      getLeafNodes(item.children, result)
    } else {
      result.push(item)
    }
  }

  return result
}

// 从targetNode开始深度遍历,找到包含在leafCodes中的节点,执行node[checkKey]=checked
export function updateNode (leafCodes = [], checked, targetNode, nodeKey = 'code', checkKey = 'checked') {
  leafCodes.includes(targetNode[nodeKey]) && targetNode[checkKey] ^ checked && (targetNode[checkKey] = checked)

  const sublist = targetNode.children || []
  sublist.forEach(node => updateNode(leafCodes, checked, node, nodeKey, checkKey))
}

// 遍历每个节点, 加上checked属性
export function parseTree(tree = [], focus = [], nodeKey = 'code', checkKey = 'checked') {
  if (!tree.length) {
    return
  }

  tree.forEach(node => {
    const contain = focus.includes(node[nodeKey]) // 是否已勾选
    node[checkKey] ^ contain && (node[checkKey] = contain)
    // 深度遍历
    Array.isArray(node['children']) && node['children'].length
    && parseTree(node['children'], focus, nodeKey, checkKey)
  })
}

// 获取key节点本身及其所有父节点的code集合
export function getParentsAndSelf (tree = [], key, nodeKey = 'code', result = []) {
  if (!tree.length) {
    return result
  }

  for (let i = 0; i < tree.length; i++) {
    const node = tree[i]
    if (node.children && node.children.length) { // 有子节点，则继续深度遍历
      result = getParentsAndSelf(node.children, key, nodeKey, result)
      // 返回长度大于0，说明已找到叶子节点，则当前父节点也应push
      result.length && result.push(node[nodeKey])
    } else if (node[nodeKey] === key) {
      result.push(node[nodeKey])
    }
    if (result.length) {
      break
    }
  }
  return result
}

// 返回key节点的所有父级节点code集合,若没找到，则返回第一层子节点
export function getParentCodes(tree = [], key, nodeKey = 'code') {
  let result = getParentsAndSelf(tree, key, nodeKey)
  // 删除第一个节点（即key节点）
  if (result[0] && result[0] === key) {
    result.splice(0, 1)
  } else if (!result.length) {
    result = tree.map(_ => _[nodeKey])
  }
  return result
}

// 遍历每个节点, 全选/取消全选
export function toggleTree(tree = [], check = true, nodeKey = 'code', checkKey = 'checked') {
  if (!tree.length) {
    return
  }

  tree.forEach(node => {
    node[checkKey] = check
    // 深度遍历
    Array.isArray(node['children']) && node['children'].length
    && toggleTree(node['children'], check, nodeKey, checkKey)
  })
}

// 递归找到所有节点, deep: true 叶子节点,false 所有节点
export function getNodes (source, result = [], deep = true) {
  if (!source) {
    return result
  }

  for (let i = 0; i < source.length; i++) {
    const item = source[i]
    if (isValidArray(item.children)) {
      !deep && result.push(item)
      getNodes(item.children, result, deep)
    } else {
      result.push(item)
    }
  }

  return result
}
